#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "netfilter_flowtable.h"

static void attr_dump(struct nfattr *attr)
{
	char *data = nla_data(attr);
	int i = 0;

	while (i < nal_len(attr)) {
		printf("%x ", *(data + i));
		i++;
		if (i % 16 == 0)
			printf("\n");
	}
	printf("\n");
}

struct ftnl_handle *ftnl_open(void)
{
	struct ftnl_handle *h = NULL;

	h = malloc(sizeof(struct ftnl_handle));
	if (!h)
		return NULL;

	h->nfnlh = nfnl_open();
	if (!h->nfnlh) {
		printf("nfnl open fail\n");
		free(h);
		return NULL;
	}

	h->ftnlssh = nfnl_subsys_open(h->nfnlh, NFNL_SUBSYS_FLOWTABLE, 1, 0);
	if (!h->ftnlssh) {
		nfnl_close(h->nfnlh);
		printf("subsys open fail\n");
		free(h);
		return NULL;
	}

	return h;
}

void ftnl_close(struct ftnl_handle *h)
{
	nfnl_subsys_close(h->ftnlssh);
	nfnl_close(h->nfnlh);
	free(h);
}

static void build_tuple(struct nlmsghdr *nlh, size_t size,
			struct flow_tuple *tuple)
{
	struct nfattr *nest_tuple, *nest_ip, *nest_proto;

	nest_tuple = nfnl_nest(nlh, size, FTA_TUPLE);

	nest_ip = nfnl_nest(nlh, size, FTA_TUPLE_IP);
	nfnl_addattr_l(nlh, size, FTA_IP_V4_SRC,
		       &tuple->sip4, sizeof(uint32_t));
	nfnl_addattr_l(nlh, size, FTA_IP_V4_DST,
		       &tuple->dip4, sizeof(uint32_t));
	nfnl_nest_end(nlh, nest_ip);

	nest_proto = nfnl_nest(nlh, size, FTA_TUPLE_PROTO);
	nfnl_addattr_l(nlh, size, FTA_PROTO_NUM,
		       &tuple->proto, sizeof(uint8_t));
	nfnl_addattr_l(nlh, size, FTA_PROTO_SPORT,
		       &tuple->sport, sizeof(uint16_t));
	nfnl_addattr_l(nlh, size, FTA_PROTO_DPORT,
		       &tuple->dport, sizeof(uint16_t));
	nfnl_nest_end(nlh, nest_proto);

	nfnl_nest_end(nlh, nest_tuple);
//	attr_dump(nest_tuple);
}

int ftnl_flush_table(struct ftnl_handle *h)
{
	struct nlmsghdr nlh;
	int ret;

	/* construct msg */
	nfnl_fill_hdr(h->ftnlssh, &nlh, 0, AF_INET, 0,
		      FT_MSG_FLUSH, NLM_F_REQUEST | NLM_F_ACK);

	/* send msg */
	ret = nfnl_send(h->nfnlh, &nlh);
	return ret;
}

int ftnl_del_flow(struct ftnl_handle *h, struct flow_tuple *tuple)
{
	const int size = 256;
	union {
		char buffer[size];
		struct nlmsghdr nlh;
	} u;
	int ret;

	/* construct msg */
	nfnl_fill_hdr(h->ftnlssh, &u.nlh, 0, AF_INET, 0,
		      FT_MSG_DEL, NLM_F_REQUEST|NLM_F_ACK);
	build_tuple(&u.nlh, size, tuple);

	/* send msg */
	ret = nfnl_send(h->nfnlh, &u.nlh);

	return ret;
}
